home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-13 / xvisrc.zip / PARAM.C < prev    next >
C/C++ Source or Header  |  1992-07-28  |  23KB  |  892 lines

  1. /* Copyright (c) 1990,1991,1992 Chris and John Downey */
  2. #ifndef lint
  3. static char *sccsid = "@(#)param.c    2.1 (Chris & John Downey) 7/29/92";
  4. #endif
  5.  
  6. /***
  7.  
  8. * program name:
  9.     xvi
  10. * function:
  11.     PD version of UNIX "vi" editor, with extensions.
  12. * module name:
  13.     param.c
  14. * module function:
  15.     Code to handle user-settable parameters. This is all pretty much
  16.     table-driven. To add a new parameter, put it in the params array,
  17.     and add a macro for it in param.h.
  18.  
  19.     The idea of the parameter table is that access to any particular
  20.     parameter has to be fast, so it is done with a table lookup. This
  21.     unfortunately means that the index of each parameter is recorded
  22.     as a macro in param.h, so that file must be changed at the same
  23.     time as the table below, and in the same way.
  24.  
  25.     When a parameter is changed, a function is called to do the actual
  26.     work; this function is part of the parameter structure.  For many
  27.     parameters, it's just a simple function that prints "not implemented";
  28.     for most others, there are "standard" functions to set bool, numeric
  29.     and string parameters, with a certain amount of checking.
  30.  
  31.     No bounds checking is done here; we should really include limits
  32.     to numeric parameters in the table. Maybe this will come later.
  33.  
  34.     The data structures will be changed again shortly to enable
  35.     buffer- and window-local parameters to be implemented.
  36.  
  37.     One problem with numeric parameters is that they are of type "int";
  38.     this obviously places some restrictions on the sort of things they
  39.     may be used for, and it may be necessary at some point to change
  40.     this type to something like "unsigned long".
  41.  
  42. * history:
  43.     STEVIE - ST Editor for VI Enthusiasts, Version 3.10
  44.     Originally by Tim Thompson (twitch!tjt)
  45.     Extensive modifications by Tony Andrews (onecom!wldrdg!tony)
  46.     Heavily modified by Chris & John Downey
  47.  
  48. ***/
  49.  
  50. #include "xvi.h"
  51.  
  52. #define nofunc    PFUNCADDR(NULL)
  53.  
  54. /*
  55.  * Default settings for string parameters.
  56.  * These are set by the exported function init_params(),
  57.  * which must be called before any parameters are accessed.
  58.  */
  59. #define    DEF_TAGS    "tags,/usr/lib/tags"
  60. #define    DEF_PARA    "^($|\\.([ILPQ]P|LI|[plib]p))"
  61. #define    DEF_SECTIONS    "^({|\\.([NS]H|HU|nh|sh))"
  62. #define    DEF_SENTENCES    "\\<[A-Z]"
  63.  
  64. /*
  65.  * Default setting for roscolour parameter is the same
  66.  * as the statuscolour if not specified otherwise.
  67.  */
  68. #ifndef    DEF_ROSCOLOUR
  69. #define    DEF_ROSCOLOUR    DEF_STCOLOUR
  70. #endif
  71.  
  72. /*
  73.  * Default settings for showing control- and meta-characters are
  74.  * as for "normal" vi, i.e. "old" xvi without SHOW_META_CHARS set.
  75.  */
  76. #ifndef    DEF_CCHARS
  77. #   define    DEF_CCHARS    FALSE
  78. #endif
  79. #ifndef    DEF_MCHARS
  80. #   define    DEF_MCHARS    FALSE
  81. #endif
  82.  
  83. /*
  84.  * Internal functions.
  85.  */
  86. static    int    strtoi P((char **));
  87. static    bool_t    _do_set P((Xviwin *, char *, bool_t));
  88. static    char    *parmstring P((Param *, int));
  89. static    void    enum_usage P((Xviwin*, Param *));
  90. static    bool_t    not_imp P((Xviwin *, Paramval, bool_t));
  91. static    bool_t    set_magic P((Xviwin *, Paramval, bool_t));
  92. static    bool_t    set_rt P((Xviwin *, Paramval, bool_t));
  93. static    char    *par_show P((void));
  94.  
  95. /*
  96.  * These are the available parameters. The following are non-standard:
  97.  *
  98.  *    autosplit format helpfile jumpscroll preserve
  99.  *    preservetime regextype vbell edit
  100.  *    colour statuscolour roscolour systemcolour
  101.  */
  102. Param    params[] = {
  103. /*  fullname        shortname       flags       value           function ... */
  104. {   "ada",          "ada",          P_BOOL,     0,              not_imp,   },
  105. {   "adapath",      "adapath",      P_STRING,   0,              not_imp,   },
  106. {   "autoindent",   "ai",           P_BOOL,     0,              nofunc,    },
  107. {   "autoprint",    "ap",           P_BOOL,     0,              not_imp,   },
  108. {   "autosplit",    "as",           P_NUM,      2,              nofunc,    },
  109. {   "autowrite",    "aw",           P_BOOL,     0,              not_imp,   },
  110. {   "beautify",     "bf",           P_BOOL,     0,              not_imp,   },
  111. {   "cchars",       "cchars",       P_BOOL,     DEF_CCHARS,     nofunc,    },
  112. {   "colour",       "co",           P_NUM,      DEF_COLOUR,     nofunc,    },
  113. {   "directory",    "dir",          P_STRING,   0,              not_imp,   },
  114. {   "edcompatible", "edcompatible", P_BOOL,     0,              not_imp,   },
  115. {   "edit",         "edit",         P_BOOL,     TRUE,           set_edit,  },
  116. {   "errorbells",   "eb",           P_BOOL,     0,              nofunc,    },
  117. {   "format",       "fmt",          P_ENUM,     0,              set_format,},
  118. {   "hardtabs",     "ht",           P_NUM,      0,              not_imp,   },
  119. {   "helpfile",     "hf",           P_STRING,   0,              nofunc,    },
  120. {   "ignorecase",   "ic",           P_BOOL,     0,              nofunc,    },
  121. {   "jumpscroll",   "js",           P_ENUM,     0,              nofunc,    },
  122. {   "lisp",         "lisp",         P_BOOL,     0,              not_imp,   },
  123. {   "list",         "ls",           P_BOOL,     0,              nofunc,    },
  124. {   "magic",        "magic",        P_BOOL,     TRUE,           set_magic, },
  125. {   "mchars",       "mchars",       P_BOOL,     DEF_MCHARS,     nofunc,    },
  126. {   "mesg",         "mesg",         P_BOOL,     0,              not_imp,   },
  127. {   "minrows",      "min",          P_NUM,      2,              nofunc,    },
  128. {   "modeline",     "modeline",     P_BOOL,     0,              not_imp,   },
  129. {   "number",       "nu",           P_BOOL,     0,              nofunc,    },
  130. {   "open",         "open",         P_BOOL,     0,              not_imp,   },
  131. {   "optimize",     "opt",          P_BOOL,     0,              not_imp,   },
  132. {   "paragraphs",   "para",         P_STRING,   0,              nofunc,    },
  133. {   "preserve",     "psv",          P_ENUM,     0,              nofunc,    },
  134. {   "preservetime", "psvt",         P_NUM,      5,              nofunc,    },
  135. {   "prompt",       "prompt",       P_BOOL,     0,              not_imp,   },
  136. {   "readonly",     "ro",           P_BOOL,     0,              nofunc,       },
  137. {   "redraw",       "redraw",       P_BOOL,     0,              not_imp,   },
  138. {   "regextype",    "rt",           P_ENUM,     0,              set_rt,    },
  139. {   "remap",        "remap",        P_BOOL,     0,              nofunc,    },
  140. {   "report",       "report",       P_NUM,      5,              nofunc,    },
  141. {   "roscolour",    "rst",          P_NUM,      DEF_ROSCOLOUR,  nofunc,    },
  142. {   "scroll",       "scroll",       P_NUM,      0,              not_imp,   },
  143. {   "sections",     "sections",     P_STRING,   0,              nofunc,    },
  144. {   "sentences",    "sentences",    P_STRING,   0,              nofunc,    },
  145. {   "shell",        "sh",           P_STRING,   0,              nofunc,    },
  146. {   "shiftwidth",   "sw",           P_NUM,      8,              nofunc,    },
  147. {   "showmatch",    "sm",           P_BOOL,     0,              nofunc,    },
  148. {   "slowopen",     "slowopen",     P_BOOL,     0,              not_imp,   },
  149. {   "sourceany",    "sourceany",    P_BOOL,     0,              not_imp,   },
  150. {   "statuscolour", "st",           P_NUM,      DEF_STCOLOUR,   nofunc,    },
  151. {   "systemcolour", "sy",           P_NUM,      DEF_SYSCOLOUR,  nofunc,    },
  152. {   "tabs",         "tabs",         P_BOOL,     TRUE,           nofunc,    },
  153. {   "tabstop",      "ts",           P_NUM,      8,              nofunc,    },
  154. {   "taglength",    "tlh",          P_NUM,      0,              nofunc,    },
  155. {   "tags",         "tags",         P_LIST,     0,              nofunc,    },
  156. {   "term",         "term",         P_STRING,   0,              not_imp,   },
  157. {   "terse",        "terse",        P_BOOL,     0,              not_imp,   },
  158. {   "timeout",      "timeout",      P_NUM,      DEF_TIMEOUT,    nofunc,    },
  159. {   "ttytype",      "ttytype",      P_STRING,   0,              not_imp,   },
  160. {   "vbell",        "vb",           P_BOOL,     0,              nofunc,    },
  161. {   "warn",         "warn",         P_BOOL,     0,              not_imp,   },
  162. {   "window",       "window",       P_NUM,      0,              not_imp,   },
  163. {   "wrapmargin",   "wm",           P_NUM,      0,              nofunc,    },
  164. {   "wrapscan",     "ws",           P_BOOL,     TRUE,           nofunc,    },
  165. {   "writeany",     "wa",           P_BOOL,     0,              not_imp,   },
  166.  
  167. {   (char *) NULL,  (char *) NULL,  0,          0,              nofunc,    },
  168.  
  169. };
  170.  
  171. /*
  172.  * Special initialisations for string, list and enum parameters,
  173.  * which we cannot put in the table above because C does not
  174.  * allow the initialisation of unions.
  175.  */
  176. static struct {
  177.     int        index;
  178.     char    *value;
  179. } init_str[] = {    /* strings and lists */
  180.     P_helpfile,        HELPFILE,
  181.     P_paragraphs,    DEF_PARA,
  182.     P_sections,        DEF_SECTIONS,
  183.     P_sentences,    DEF_SENTENCES,
  184.     P_tags,        DEF_TAGS,
  185. };
  186. #define    NSTRS    (sizeof(init_str) / sizeof(init_str[0]))
  187.  
  188. /*
  189.  * Names of values for the P_jumpscroll enumerated parameter.
  190.  *
  191.  * It is essential that these are in the same order as the js_...
  192.  * symbolic constants defined in xvi.h.
  193.  */
  194. static char *js_strings[] =
  195. {
  196.     "off",        /* js_OFF */
  197.     "auto",        /* js_AUTO */
  198.     "on",        /* js_ON */
  199.     NULL
  200. };
  201.  
  202. static struct {
  203.     int        index;
  204.     int        value;
  205.     char    **elist;
  206. } init_enum[] = {    /* enumerations */
  207.     P_format,        DEF_TFF,    fmt_strings,
  208.     P_jumpscroll,    js_AUTO,    js_strings,
  209.     P_preserve,        psv_STANDARD,    psv_strings,
  210.     P_regextype,    rt_GREP,    rt_strings,
  211. };
  212. #define    NENUMS    (sizeof(init_enum) / sizeof(init_enum[0]))
  213.  
  214. /*
  215.  * These are used by par_show().
  216.  */
  217. static    bool_t    show_all;
  218. static    Param    *curparam;
  219.  
  220. /*
  221.  * Initialise parameters.
  222.  *
  223.  * This function is called once from startup().
  224.  */
  225. void
  226. init_params()
  227. {
  228.     Paramval    pv;
  229.     Param    *pp;
  230.     int        i;
  231.  
  232.     /*
  233.      * First go through the special string and enum initialisation
  234.      * tables, setting the values into the union field in the
  235.      * parameter structures.
  236.      */
  237.     for (i = 0; i < NSTRS; i++) {
  238.     set_param(init_str[i].index, init_str[i].value);
  239.     }
  240.     for (i = 0; i < NENUMS; i++) {
  241.     set_param(init_enum[i].index, init_enum[i].value,
  242.             init_enum[i].elist);
  243.     }
  244.  
  245.     /*
  246.      * Call any special functions that have been set up for
  247.      * any parameters, using the default values included in
  248.      * the parameter table.
  249.      */
  250.     for (pp = ¶ms[0]; pp->p_fullname != NULL; pp++) {
  251.     if (pp->p_func != nofunc && pp->p_func != PFUNCADDR(not_imp)) {
  252.         switch (pp->p_flags & P_TYPE) {
  253.         case P_NUM:
  254.         case P_ENUM:
  255.         pv.pv_i = pp->p_value;
  256.         break;
  257.         case P_BOOL:
  258.         pv.pv_b = pp->p_value;
  259.         break;
  260.         case P_STRING:
  261.         pv.pv_s = pp->p_str;
  262.         break;
  263.         case P_LIST:
  264.         pv.pv_l = pp->p_list;
  265.         }
  266.         (void) (*pp->p_func)(curwin, pv, FALSE);
  267.     }
  268.     }
  269. }
  270.  
  271. void
  272. do_set(window, argc, argv, inter)
  273. Xviwin    *window;
  274. int    argc;        /* number of parameters to set */
  275. char    *argv[];    /* vector of parameter strings */
  276. bool_t    inter;        /* TRUE if called interactively */
  277. {
  278.     int    count;
  279.  
  280.     /*
  281.      * First check to see if there were any parameters to set,
  282.      * or if the user just wants us to display the parameters.
  283.      */
  284.     if (argc == 0 || (argc == 1 && (argv[0][0] == '\0' ||
  285.                 strncmp(argv[0], "all", 3) == 0))) {
  286.     if (inter) {
  287.         int pcwidth;
  288.  
  289.         show_all = (argc != 0 && argv[0][0] != '\0');
  290.         curparam = ¶ms[0];
  291.         pcwidth = (window->w_ncols < 90 ?
  292.             window->w_ncols :
  293.             (window->w_ncols < 135 ?
  294.                 window->w_ncols / 2 :
  295.                 window->w_ncols / 3));
  296.  
  297.         disp_init(window, par_show, pcwidth, FALSE);
  298.     }
  299.  
  300.     return;
  301.     }
  302.  
  303.     for (count = 0; count < argc; count++) {
  304.     if (!_do_set(window, argv[count], inter)) {
  305.         break;
  306.     }
  307.     }
  308.  
  309.     if (inter) {
  310.  
  311.     /*
  312.      * Finally, update the screen in case we changed
  313.      * something like "tabstop" or "list" that will change
  314.      * its appearance. We don't always have to do this,
  315.      * but it's easier for now.
  316.      */
  317.     update_all();
  318.     }
  319. }
  320.  
  321. /*
  322.  * Convert a string to an integer. The string may encode the integer
  323.  * in octal, decimal or hexadecimal form, in the same style as C. On
  324.  * return, make the string pointer, which is passed to us by
  325.  * reference, point to the first character which isn't valid for the
  326.  * base the number seems to be in.
  327.  */
  328. static int
  329. strtoi(sp)
  330. char    **sp;
  331. {
  332.     register char    *s;
  333.     register int    i, c;
  334.     bool_t        neg;
  335.  
  336.     i = 0;
  337.     neg = FALSE;
  338.     s = *sp;
  339.     c = *s;
  340.     while (is_space(c)) {
  341.     c = *++s;
  342.     }
  343.     if (c == '-') {
  344.     neg = TRUE;
  345.     c = *++s;
  346.     }
  347.     while (is_space(c)) {
  348.     c = *++s;
  349.     }
  350.     if (c == '0') {
  351.     switch (c = *++s) {
  352.     case 'x': case 'X':
  353.         /*
  354.          * We've got 0x ... or 0X ..., so it
  355.          * looks like a hex. number.
  356.          */
  357.         while ((c = *++s) != '\0' && is_xdigit(c)) {
  358.         i = (i * 16) + hex_to_bin(c);
  359.         }
  360.         break;
  361.  
  362.     case '0': case '1': case '2': case '3':
  363.     case '4': case '5': case '6': case '7':
  364.         /*
  365.          * It looks like an octal number.
  366.          */
  367.         do {
  368.         i = (i * 8) + c - '0';
  369.         } while ((c = *++s) != '\0' && is_octdigit(c));
  370.         break;
  371.  
  372.     default:
  373.         *sp = s;
  374.         return(0);
  375.     }
  376.     } else {
  377.     /*
  378.      * Assume it's decimal.
  379.      */
  380.     while (c != '\0' && is_digit(c)) {
  381.         i = (i * 10) + c - '0';
  382.         c = *++s;
  383.     }
  384.     }
  385.     *sp = s;
  386.     return(neg ? -i : i);
  387. }
  388.  
  389. /*
  390.  * Internal version of do_set(). Returns TRUE if set of specified
  391.  * parameter was successful, otherwise FALSE.
  392.  */
  393. static bool_t
  394. _do_set(window, arg, inter)
  395. Xviwin    *window;
  396. char    *arg;                /* parameter string */
  397. bool_t    inter;                /* TRUE if called interactively */
  398. {
  399.     int        settype = 0;        /* type they want to set */
  400.     bool_t    bool_value;        /* value they want to set */
  401.     char    *str_value;        /* value they want to set */
  402.     Param    *pp;
  403.     Paramval    val;
  404.     char    *cp;
  405.     char    **ep;
  406.  
  407.  
  408.     /*
  409.      * "arg" points at the parameter we are going to try to set.
  410.      * Spot "no" and "=" keys.
  411.      */
  412.  
  413.     /*
  414.      * Note that we will have to change this later if we
  415.      * want to implement "nomatch" and "nonomatch". :-(
  416.      */
  417.     if (strncmp(arg, "no", 2) == 0) {
  418.     settype = P_BOOL;
  419.     bool_value = FALSE;
  420.     arg += 2;
  421.     } else {
  422.     bool_value = TRUE;
  423.     }
  424.  
  425.     str_value = strchr(arg, '=');
  426.     if (str_value != NULL) {
  427.     if (settype == P_BOOL) {
  428.         if (inter) {
  429.         show_error(window, "Can't give \"no\" and a value");
  430.         return(FALSE);
  431.         }
  432.     }
  433.  
  434.     /*
  435.      * Null-terminate the parameter name
  436.      * and point str_value at the value to
  437.      * the right of the '='.
  438.      */
  439.     *str_value++ = '\0';
  440.     settype = P_STRING;
  441.  
  442.     } else if (settype != P_BOOL) {
  443.  
  444.     /*
  445.      * Not already set to P_BOOL, so we haven't seen a "no".
  446.      * No '=' sign, so assume we are setting a boolean
  447.      * parameter to TRUE.
  448.      */
  449.     settype = P_BOOL;
  450.     bool_value = TRUE;
  451.     }
  452.  
  453.     /*
  454.      * Now search for a complete match of the parameter
  455.      * name with either the full or short name in the
  456.      * parameter table.
  457.      */
  458.     for (pp = ¶ms[0]; pp->p_fullname != NULL; pp++) {
  459.     if (strcmp(arg, pp->p_fullname) == 0 ||
  460.         strcmp(arg, pp->p_shortname) == 0)
  461.         break;
  462.     }
  463.  
  464.     if (pp->p_fullname == NULL) {        /* no match found */
  465.     if (inter) {
  466.         show_error(window, "No such parameter");
  467.         return(FALSE);
  468.     }
  469.     }
  470.  
  471.     /*
  472.      * Check the passed type is appropriate for the
  473.      * parameter's type. If it isn't, winge and return.
  474.      */
  475.     switch (pp->p_flags & P_TYPE) {
  476.     case P_STRING:
  477.     case P_LIST:
  478.     case P_NUM:
  479.     if (settype != P_STRING) {
  480.         if (inter) {
  481.         show_error(window,
  482.             (pp->p_flags & P_STRING) ?
  483.             "Invalid set of string parameter"
  484.             : (pp->p_flags & P_NUM) ?
  485.             "Invalid set of numeric parameter"
  486.             : /* else */
  487.             "Invalid set of list parameter");
  488.         }
  489.         return(FALSE);
  490.     }
  491.     break;
  492.  
  493.     case P_ENUM:
  494.     if (settype != P_STRING) {
  495.         if (inter) {
  496.         enum_usage(window, pp);
  497.         }
  498.         return(FALSE);
  499.     }
  500.     break;
  501.  
  502.     case P_BOOL:
  503.     if (settype != P_BOOL) {
  504.         if (inter) {
  505.         show_error(window, "Invalid set of boolean parameter");
  506.         }
  507.         return(FALSE);
  508.     }
  509.     }
  510.  
  511.     /*
  512.      * Do any type-specific checking, and set up the
  513.      * "val" union to contain the (decoded) value.
  514.      */
  515.     switch (pp->p_flags & P_TYPE) {
  516.     case P_NUM:
  517.     {
  518.     int i;
  519.  
  520.     cp = str_value;
  521.     i = strtoi(&cp);
  522.     /*
  523.      * If there are extra characters after the number,
  524.      * don't accept it.
  525.      */
  526.     if (*cp != '\0') {
  527.         if (inter) {
  528.         show_error(window, "Invalid numeric parameter");
  529.         }
  530.         return(FALSE);
  531.     }
  532.  
  533.     val.pv_i = i;
  534.     break;
  535.     }
  536.  
  537.     case P_ENUM:
  538.     for (ep = pp->p_elist; *ep != NULL; ep++) {
  539.         if (strcmp(*ep, str_value) == 0)
  540.         break;
  541.     }
  542.  
  543.     if (*ep == NULL) {
  544.         if (inter) {
  545.         enum_usage(window, pp);
  546.         }
  547.         return(FALSE);
  548.     }
  549.  
  550.     val.pv_i = ep - pp->p_elist;
  551.     break;
  552.  
  553.     case P_STRING:
  554.     case P_LIST:
  555.     val.pv_s = str_value;
  556.     break;
  557.  
  558.     case P_BOOL:
  559.     val.pv_b = bool_value;
  560.     break;
  561.     }
  562.  
  563.     /*
  564.      * Call the check function if there is one.
  565.      */
  566.     if (pp->p_func != nofunc && (*pp->p_func)(window, val, inter) == FALSE) {
  567.     return(FALSE);
  568.     }
  569.  
  570.     /*
  571.      * Set the value.
  572.      */
  573.     switch (pp->p_flags & P_TYPE) {
  574.     case P_NUM:
  575.     case P_ENUM:
  576.     pp->p_value = val.pv_i;
  577.     break;
  578.  
  579.     case P_BOOL:
  580.     pp->p_value = bool_value;
  581.     break;
  582.  
  583.     case P_STRING:
  584.     case P_LIST:
  585.     set_param(pp - params, str_value);
  586.     break;
  587.     }
  588.     pp->p_flags |= P_CHANGED;
  589.  
  590.     /*
  591.      * Check the bounds for numeric parameters here.
  592.      * We will have to make this table-driven later.
  593.      */
  594.     if (Pn(P_tabstop) <= 0 || Pn(P_tabstop) > MAX_TABSTOP) {
  595.     if (inter) {
  596.         show_error(window, "Invalid tab size specified");
  597.     }
  598.     set_param(P_tabstop, 8);
  599.     return(FALSE);
  600.     }
  601.  
  602.     /*
  603.      * Got through all the bounds checking, so we're okay.
  604.      */
  605.     return TRUE;
  606. }
  607.  
  608. /*
  609.  * Internal parameter setting - parameters are not considered
  610.  * to have been changed unless they are set by the user.
  611.  *
  612.  * All types of parameter are handled by this function.
  613.  * Enumerated types are special, because two arguments
  614.  * are expected: the first, always present, is the index,
  615.  * but the second may be either a valid list of strings
  616.  * a NULL pointer, the latter indicating that the list
  617.  * of strings is not to be changed.
  618.  *
  619.  * The P_LIST type accepts a string argument and converts
  620.  * it to a vector of strings which is then stored.
  621.  */
  622. /*VARARGS1*/
  623. void
  624. #ifdef    __STDC__
  625.     set_param(int n, ...)
  626. #else
  627.     set_param(n, va_alist)
  628.     int        n;
  629.     va_dcl
  630. #endif
  631. {
  632.     va_list        argp;
  633.     Param        *pp;
  634.     char        *cp;
  635.     char        **elist;
  636.  
  637.     pp = ¶ms[n];
  638.  
  639.     VA_START(argp, n);
  640.  
  641.     switch (pp->p_flags & P_TYPE) {
  642.     case P_ENUM:
  643.     pp->p_value = va_arg(argp, int);
  644.  
  645.     /*
  646.      * If the second argument is a non-NULL list of
  647.      * strings, set it into the parameter structure.
  648.      * Note that this is not dependent on the return
  649.      * value from the check function being TRUE,
  650.      * since the check cannot be made until the
  651.      * array of strings is in place.
  652.      */
  653.     elist = va_arg(argp, char **);
  654.     if (elist != NULL) {
  655.         pp->p_elist = elist;
  656.     }
  657.     break;
  658.  
  659.     case P_BOOL:
  660.     case P_NUM:
  661.     pp->p_value = va_arg(argp, int);
  662.     break;
  663.  
  664.     case P_LIST:
  665.     {
  666.         int    argc;
  667.         char    **argv;
  668.  
  669.         cp = strsave(va_arg(argp, char *));
  670.         if (cp == NULL) {
  671.         /*
  672.          * This is not necessarily a good idea.
  673.          */
  674.         show_error(curwin, "Can't allocate memory for parameter");
  675.         return;
  676.         }
  677.  
  678.         makeargv(cp, &argc, &argv, " \t,");
  679.         if (argc == 0 || argv == NULL) {
  680.         free(cp);
  681.         return;
  682.         }
  683.         if (pp->p_list != NULL) {
  684.         if (pp->p_list[0] != NULL) {
  685.             free(pp->p_list[0]);
  686.         }
  687.         free((char *) pp->p_list);
  688.         }
  689.         pp->p_list = argv;
  690.     }
  691.     break;
  692.  
  693.     case P_STRING:
  694.     cp = strsave(va_arg(argp, char *));
  695.     if (cp == NULL) {
  696.         /*
  697.          * This is not necessarily a good idea.
  698.          */
  699.         show_error(curwin, "Can't allocate memory for parameter");
  700.     } else {
  701.         /*
  702.          * We always free up the old string, because
  703.          * it must have been allocated at some point.
  704.          */
  705.         if (pp->p_str != NULL) {
  706.         free(pp->p_str);
  707.         }
  708.         pp->p_str = cp;
  709.     }
  710.     break;
  711.     }
  712.  
  713.     va_end(argp);
  714. }
  715.  
  716. /*
  717.  * Display helpful usage message for an enumerated parameter, listing
  718.  * the legal values for it.
  719.  */
  720. static void
  721. enum_usage(w, pp)
  722.     Xviwin        *w;
  723.     Param        *pp;
  724. {
  725.     Flexbuf        s;
  726.     char        **sp;
  727.  
  728.     flexnew(&s);
  729.     (void) lformat(&s, "Must be one of:");
  730.     for (sp = (char **) pp->p_str; *sp != NULL; sp++) {
  731.     (void) lformat(&s, " %s", *sp);
  732.     }
  733.     show_error(w, "%s", flexgetstr(&s));
  734.     flexdelete(&s);
  735. }
  736.  
  737. /*
  738.  * Return a string representation for a single parameter.
  739.  */
  740. static char *
  741. parmstring(pp, leading)
  742. Param    *pp;            /* parameter */
  743. int    leading;        /* number of leading spaces in string */
  744. {
  745.     static Flexbuf    b;
  746.  
  747.     flexclear(&b);
  748.     while (leading-- > 0) {
  749.     (void) flexaddch(&b, ' ');
  750.     }
  751.     switch (pp->p_flags & P_TYPE) {
  752.     case P_BOOL:
  753.     (void) lformat(&b, "%s%s", (pp->p_value ? "" : "no"), pp->p_fullname);
  754.     break;
  755.  
  756.     case P_NUM:
  757.     (void) lformat(&b, "%s=%d", pp->p_fullname, pp->p_value);
  758.     break;
  759.  
  760.     case P_ENUM:
  761.     {
  762.     int    n;
  763.     char    *estr;
  764.  
  765.     for (n = 0; ; n++) {
  766.         if ((estr = ((char **) pp->p_str)[n]) == NULL) {
  767.         estr = "INTERNAL ERROR";
  768.         break;
  769.         }
  770.         if (n == pp->p_value)
  771.         break;
  772.     }
  773.     (void) lformat(&b, "%s=%s", pp->p_fullname, estr);
  774.     break;
  775.     }
  776.  
  777.     case P_STRING:
  778.     (void) lformat(&b, "%s=%s", pp->p_fullname,
  779.                     (pp->p_str != NULL) ? pp->p_str : "");
  780.     break;
  781.  
  782.     case P_LIST:
  783.     {
  784.         register char    **cpp;
  785.  
  786.         (void) lformat(&b, "%s=%s", pp->p_fullname, pp->p_list[0]);
  787.         for (cpp = pp->p_list + 1; *cpp != NULL; cpp++) {
  788.         (void) lformat(&b, " %s", *cpp);
  789.         }
  790.     }
  791.     break;
  792.     }
  793.     return(flexgetstr(&b));
  794. }
  795.  
  796. static char *
  797. par_show()
  798. {
  799.     static bool_t    started = FALSE;
  800.  
  801.     if (!started) {
  802.     started = TRUE;
  803.     return("Parameters:");
  804.     }
  805.  
  806.     for ( ; curparam->p_fullname != NULL; curparam++) {
  807.  
  808.     /*
  809.      * Ignore unimplemented parameters.
  810.      */
  811.     if (curparam->p_func != PFUNCADDR(not_imp)) {
  812.         /*
  813.          * Display all parameters if show_all is set;
  814.          * otherwise, just display changed parameters.
  815.          */
  816.         if (show_all || (curparam->p_flags & P_CHANGED) != 0) {
  817.         break;
  818.         }
  819.     }
  820.     }
  821.  
  822.     if (curparam->p_fullname == NULL) {
  823.     started = FALSE;        /* reset for next time */
  824.     return(NULL);
  825.     } else {
  826.     char    *retval;
  827.  
  828.     retval = parmstring(curparam, 3);
  829.     curparam++;
  830.     return(retval);
  831.     }
  832. }
  833.  
  834. /*ARGSUSED*/
  835. static bool_t
  836. not_imp(window, new_value, interactive)
  837. Xviwin        *window;
  838. Paramval    new_value;
  839. bool_t        interactive;
  840. {
  841.     if (interactive) {
  842.     show_message(window, "That parameter is not implemented!");
  843.     }
  844.     return(TRUE);
  845. }
  846.  
  847. /*ARGSUSED*/
  848. static bool_t
  849. set_magic(window, new_value, interactive)
  850. Xviwin            *window;
  851. Paramval        new_value;
  852. bool_t            interactive;
  853. {
  854.     static int    prev_rt = rt_GREP;
  855.  
  856.     if (new_value.pv_b) {
  857.     /*
  858.      * Turn magic on.
  859.      */
  860.     if (Pn(P_regextype) == rt_TAGS) {
  861.         set_param(P_regextype, prev_rt, (char **) NULL);
  862.     }
  863.     } else {
  864.     /*
  865.      * Turn magic off.
  866.      */
  867.     if (Pn(P_regextype) != rt_TAGS) {
  868.         prev_rt = Pn(P_regextype);
  869.         set_param(P_regextype, rt_TAGS, (char **) NULL);
  870.     }
  871.     }
  872.     return(TRUE);
  873. }
  874.  
  875. /*ARGSUSED*/
  876. static bool_t
  877. set_rt(window, new_value, interactive)
  878. Xviwin        *window;
  879. Paramval    new_value;
  880. bool_t        interactive;
  881. {
  882.     switch (new_value.pv_i) {
  883.     case rt_TAGS:
  884.     case rt_GREP:
  885.     case rt_EGREP:
  886.     set_param(P_magic, (new_value.pv_i != rt_TAGS));
  887.     return(TRUE);
  888.     default:
  889.     return(FALSE);
  890.     }
  891. }
  892.